// Copyright (C) Kumo inc. and its affiliates.
// Author: Jeff.li lijippy@163.com
// All rights reserved.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
//

#pragma once

#include <cantor/common/type_list.h>
#include <cantor/common/expr_class.h>
#include <cantor/unresolved/clause/constant_expr.h>
#include <cantor/unresolved/clause/range_var.h>
#include <cantor/unresolved/clause/row_expr.h>
#include <cantor/unresolved/ddls/column_option.h>
#include <cantor/unresolved/ddls/enum_element.h>
#include <cantor/unresolved/ddls/index_opt.h>
#include <cantor/unresolved/ddls/column_def.h>
#include <cantor/unresolved/ddls/partition_option.h>
#include <cantor/unresolved/ddls/partition_range.h>
#include <cantor/unresolved/ddls/table_partition_option.h>
#include <cantor/unresolved/ddls/table_option.h>
#include <cantor/unresolved/ddls/constraint.h>
#include <cantor/unresolved/ddls/database_option.h>
#include <cantor/unresolved/ddls/alter_table_spec.h>
#include <cantor/unresolved/dqls/by_item.h>
#include <cantor/unresolved/dqls/order_by_clause.h>
#include <cantor/unresolved/dqls/group_by_clause.h>
#include <cantor/unresolved/dqls/limit_clause.h>
#include <cantor/unresolved/dqls/indirection.h>
#include <cantor/unresolved/dqls/select_field.h>
#include <cantor/unresolved/dqls/index_hint.h>
#include <cantor/unresolved/dqls/select_stmt_opts.h>
#include <cantor/unresolved/dqls/table_source.h>
#include <cantor/unresolved/dqls/join_node.h>
#include <cantor/unresolved/dqls/subquery_expr.h>
#include <cantor/unresolved/dqls/exists_subquery_expr.h>
#include <cantor/unresolved/dqls/common_table_expr.h>
#include <cantor/unresolved/dqls/with_clause.h>
#include <cantor/unresolved/dqls/compare_subquery_expr.h>
#include <cantor/unresolved/dqls/where_clause.h>
#include <cantor/unresolved/dqls/having_clause.h>
#include <cantor/unresolved/dqls/table_ref.h>
#include <cantor/unresolved/dmls/assignment.h>
#include <cantor/unresolved/dmls/field_item.h>
#include <cantor/unresolved/dmls/lines_clause.h>
#include <cantor/unresolved/dmls/fields_clause.h>
#include <cantor/unresolved/functions/func_expr.h>
#include <cantor/unresolved/functions/func_when_clause.h>
#include <cantor/unresolved/functions/func_case_when_clause.h>
#include <cantor/unresolved/clause/index_lock_opt.h>
#include <cantor/unresolved/clause/algorithm_opt.h>
#include <cantor/unresolved/clause/var_assign.h>
#include <cantor/unresolved/clause/named_type.h>
#include <cantor/unresolved/clause/namespace_option.h>
#include <cantor/unresolved/clause/when_clause_case.h>
#include <cantor/unresolved/clause/when_clause.h>
#include <cantor/unresolved/dcls/user_identity.h>
#include <cantor/unresolved/dcls/user_spec.h>
#include <cantor/unresolved/dcls/auth_option.h>
#include <cantor/unresolved/dcls/priv_level.h>
#include <cantor/unresolved/dcls/priv_type.h>
#include <cantor/unresolved/ctors/map_pair.h>
#include <cantor/unresolved/ctors/dict_pair.h>
#include <cantor/unresolved/ctors/map_arg.h>
#include <cantor/unresolved/ctors/dict_arg.h>
#include <cantor/unresolved/ctors/expr_list_arg.h>
#include <cantor/unresolved/ctors/enum_arg.h>
#include <cantor/unresolved/ctors/proto_arg.h>
#include <cantor/unresolved/ctors/udf_arg.h>
#include <cantor/unresolved/functions/ctor_map_func_expr.h>
#include <cantor/unresolved/functions/ctor_struct_func_expr.h>
#include <cantor/unresolved/functions/ctor_union_func_expr.h>
#include <cantor/unresolved/functions/ctor_array_func_expr.h>
#include <cantor/unresolved/functions/ctor_set_func_expr.h>
#include <cantor/unresolved/functions/ctor_tuple_func_expr.h>
#include <cantor/unresolved/functions/ctor_json_func_expr.h>
#include <cantor/unresolved/functions/ctor_json_array_func_expr.h>
#include <cantor/unresolved/functions/ctor_enum_func_expr.h>
#include <cantor/unresolved/functions/ctor_proto_func_expr.h>
#include <cantor/unresolved/functions/ctor_udf_func_expr.h>
#include <cantor/unresolved/clause/table_name.h>
#include <cantor/unresolved/clause/type_name_uri.h>
#include <cantor/unresolved/clause/column_name.h>

namespace cantor::unresolved {
    ///////////////////////////////////////////////////////////////////////////////
    ///
    ///////////////////////////////////////////////////////////////////////////////

    template<cantor::pb::ast::ExprNodeType type>
    struct ExpressionTypeTrait;

    /// UnresolvedConstExpr
    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_CONSTANT_EXPR> {
        using type = UnresolvedConstExpr;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_CONSTANT_EXPR;

        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DISPATCH, cantor::pb::ast::ENC_DDL,
                                                cantor::pb::ast::ENC_DCL, cantor::pb::ast::ENC_DML, cantor::pb::ast::ENC_DML);
    };


    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_RANGE_VAR> {
        using type = UnresolvedRangeVar;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_RANGE_VAR;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DISPATCH, cantor::pb::ast::ENC_DDL,
                                                cantor::pb::ast::ENC_DCL, cantor::pb::ast::ENC_DML, cantor::pb::ast::ENC_DML,
                                                cantor::pb::ast::ENC_INDIRECTION);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_ROW_EXPR> {
        using type = UnresolvedRowExpr;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_ROW_EXPR;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DISPATCH, cantor::pb::ast::ENC_DDL,
                                                cantor::pb::ast::ENC_DML, cantor::pb::ast::ENC_DML);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_COLUMN_OPT> {
        using type = UnresolvedColumnOption;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_COLUMN_OPT;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DEFINITE, cantor::pb::ast::ENC_DDL);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_ENUM_ELEMENT> {
        using type = UnresolvedEnumElement;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_ENUM_ELEMENT;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DEFINITE, cantor::pb::ast::ENC_DDL);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_INDEX_OPT> {
        using type = UnresolvedIndexOption;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_INDEX_OPT;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DEFINITE, cantor::pb::ast::ENC_DDL);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_COLUMN_DEF> {
        using type = UnresolvedColumnDef;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_COLUMN_DEF;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DEFINITE, cantor::pb::ast::ENC_DDL);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_PARTITION_OPT> {
        using type = UnresolvedPartitionOption;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_PARTITION_OPT;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DEFINITE, cantor::pb::ast::ENC_DDL);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_PARTITION_RANGE> {
        using type = UnresolvedPartitionRange;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_PARTITION_RANGE;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DEFINITE, cantor::pb::ast::ENC_DDL);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_TABLE_PARTITION_OPTION> {
        using type = UnresolvedTablePartitionOption;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_TABLE_PARTITION_OPTION;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DEFINITE, cantor::pb::ast::ENC_DDL);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_TABLE_OPT> {
        using type = UnresolvedTableOption;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_TABLE_OPT;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DEFINITE, cantor::pb::ast::ENC_DDL);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_CONSTRAINT> {
        using type = UnresolvedConstraint;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_CONSTRAINT;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DEFINITE, cantor::pb::ast::ENC_DDL);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_DATABASE_OPT> {
        using type = UnresolvedDatabaseOption;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_DATABASE_OPT;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DEFINITE, cantor::pb::ast::ENC_DDL);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_ALTER_SEPC> {
        using type = UnresolvedAlterTableSpec;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_ALTER_SEPC;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DEFINITE, cantor::pb::ast::ENC_DDL);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_BY_ITEM> {
        using type = UnresolvedByItem;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_BY_ITEM;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DEFINITE, cantor::pb::ast::ENC_DQL);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_ORDER_BY> {
        using type = UnresolvedOrderByClause;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_ORDER_BY;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DEFINITE, cantor::pb::ast::ENC_DQL);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_GROUP_BY> {
        using type = UnresolvedGroupByClause;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_GROUP_BY;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DEFINITE, cantor::pb::ast::ENC_DQL);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_LIMIT_CLAUSE> {
        using type = UnresolvedLimitClause;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_LIMIT_CLAUSE;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DEFINITE, cantor::pb::ast::ENC_DQL);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_INDIRECTION> {
        using type = UnresolvedIndirection;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_INDIRECTION;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DEFINITE, cantor::pb::ast::ENC_DQL);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_SELECT_FIELD> {
        using type = UnresolvedSelectField;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_SELECT_FIELD;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DEFINITE, cantor::pb::ast::ENC_DQL);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_INDEX_HINT> {
        using type = UnresolvedIndexHint;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_INDEX_HINT;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DEFINITE, cantor::pb::ast::ENC_DQL);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_SELECT_STMT_OPT> {
        using type = UnresolvedSelectStmtOpts;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_SELECT_STMT_OPT;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DEFINITE, cantor::pb::ast::ENC_DQL);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_TABLE_SOURCE> {
        using type = UnresolvedTableSource;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_TABLE_SOURCE;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DEFINITE, cantor::pb::ast::ENC_DQL);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_JOIN_NODE> {
        using type = UnresolvedJoinNode;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_JOIN_NODE;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DEFINITE, cantor::pb::ast::ENC_DQL);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_SUB_QUERY_EXPR> {
        using type = UnresolvedSubqueryExpr;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_SUB_QUERY_EXPR;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DISPATCH, cantor::pb::ast::ENC_DQL);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_EXISTS_SUB_QUERY_EXPR> {
        using type = UnresolvedExistsSubqueryExpr;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_EXISTS_SUB_QUERY_EXPR;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DISPATCH, cantor::pb::ast::ENC_DQL);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_COMMON_TABLE_EXPR> {
        using type = UnresolvedCommonTableExpr;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_COMMON_TABLE_EXPR;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DISPATCH, cantor::pb::ast::ENC_DQL);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_WITH_CLAUSE> {
        using type = UnresolvedWithClause;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_WITH_CLAUSE;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DEFINITE, cantor::pb::ast::ENC_DQL);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_COMPARE_SUBQUERY_EXPR> {
        using type = UnresolvedCompareSubqueryExpr;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_COMPARE_SUBQUERY_EXPR;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DISPATCH, cantor::pb::ast::ENC_DQL);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_WHERE_CLAUSE> {
        using type = UnresolvedWhereClause;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_WHERE_CLAUSE;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DEFINITE, cantor::pb::ast::ENC_DQL);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_HAVING_CLAUSE> {
        using type = UnresolvedHavingClause;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_HAVING_CLAUSE;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DEFINITE, cantor::pb::ast::ENC_DQL);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_ASSIGNMENT> {
        using type = UnresolvedAssignment;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_ASSIGNMENT;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DEFINITE, cantor::pb::ast::ENC_DML);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_FIELD_ITEM> {
        using type = UnresolvedFieldItem;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_FIELD_ITEM;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DEFINITE, cantor::pb::ast::ENC_DML);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_LINE_CLAUSE> {
        using type = UnresolvedLinesClause;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_LINE_CLAUSE;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DEFINITE, cantor::pb::ast::ENC_DML);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_FIELD_CLAUSE> {
        using type = UnresolvedFieldsClause;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_FIELD_CLAUSE;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DEFINITE, cantor::pb::ast::ENC_DML);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_FUNC_EXPR> {
        using type = UnresolvedFuncExpr;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_FUNC_EXPR;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DISPATCH, cantor::pb::ast::ENC_FUNC);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_FUNC_WHEN_CLAUSE> {
        using type = UnresolvedFuncWhenClause;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_FUNC_WHEN_CLAUSE;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DISPATCH, cantor::pb::ast::ENC_FUNC);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_FUNC_CASE_WHEN_CLAUSE> {
        using type = UnresolvedFuncCaseWhenClause;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_FUNC_CASE_WHEN_CLAUSE;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DISPATCH, cantor::pb::ast::ENC_FUNC);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_INDEX_LOCK_OPT> {
        using type = UnresolvedIndexLockOpt;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_INDEX_LOCK_OPT;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DEFINITE, cantor::pb::ast::ENC_CLAUSE);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_ALGORITHM_OPT> {
        using type = UnresolvedAlgorithmOpt;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_ALGORITHM_OPT;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DEFINITE, cantor::pb::ast::ENC_CLAUSE);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_VAR_ASSIGN> {
        using type = UnresolvedVarAssign;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_VAR_ASSIGN;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DEFINITE, cantor::pb::ast::ENC_CLAUSE);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_NAMED_TYPE> {
        using type = UnresolvedNamedType;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_NAMED_TYPE;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DEFINITE, cantor::pb::ast::ENC_CLAUSE);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_NAMESPACE_OPT> {
        using type = UnresolvedNamespaceOption;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_NAMESPACE_OPT;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DEFINITE, cantor::pb::ast::ENC_CLAUSE);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_CLAUSE_WHEN_CASE> {
        using type = UnresolvedWhenClauseCase;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_CLAUSE_WHEN_CASE;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DEFINITE, cantor::pb::ast::ENC_CLAUSE);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_CLAUSE_WHEN> {
        using type = UnresolvedWhenClause;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_CLAUSE_WHEN;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DEFINITE, cantor::pb::ast::ENC_CLAUSE);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_COLUM_NAME> {
        using type = UnresolvedColumnName;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_COLUM_NAME;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DEFINITE, cantor::pb::ast::ENC_CLAUSE);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_TABLE_NAME> {
        using type = UnresolvedTableName;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_TABLE_NAME;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DEFINITE, cantor::pb::ast::ENC_CLAUSE);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_TYPE_NAME_URI> {
        using type = UnresolvedTypeNameUri;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_TYPE_NAME_URI;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DEFINITE, cantor::pb::ast::ENC_CLAUSE);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_USER_IDENTIFIER> {
        using type = UnresolvedUserIdentity;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_USER_IDENTIFIER;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DEFINITE, cantor::pb::ast::ENC_CLAUSE);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_USER_SPEC> {
        using type = UnresolvedUserSpec;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_USER_SPEC;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DEFINITE, cantor::pb::ast::ENC_CLAUSE);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_AUTH_OPTION> {
        using type = UnresolvedAuthOption;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_AUTH_OPTION;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DEFINITE, cantor::pb::ast::ENC_CLAUSE);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_PRIV_LEVEL> {
        using type = UnresolvedPrivLevel;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_PRIV_LEVEL;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DEFINITE, cantor::pb::ast::ENC_CLAUSE);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_PRIV_TYPE> {
        using type = UnresolvedPrivType;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_PRIV_TYPE;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DEFINITE, cantor::pb::ast::ENC_CLAUSE);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_MAP_PAIR> {
        using type = UnresolvedMapPair;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_MAP_PAIR;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DEFINITE, cantor::pb::ast::ENC_CLAUSE,
                                                cantor::pb::ast::ENC_CTOR);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_DICT_PAIR> {
        using type = UnresolvedDictPair;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_DICT_PAIR;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DEFINITE, cantor::pb::ast::ENC_CLAUSE,
                                                cantor::pb::ast::ENC_CTOR);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_MAP_ARG> {
        using type = UnresolvedMapArg;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_MAP_ARG;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DEFINITE, cantor::pb::ast::ENC_CLAUSE,
                                                cantor::pb::ast::ENC_CTOR);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_DICT_ARG> {
        using type = UnresolvedDictArg;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_DICT_ARG;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DEFINITE, cantor::pb::ast::ENC_CLAUSE,
                                                cantor::pb::ast::ENC_CTOR);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_EXPR_LIST_ARG> {
        using type = UnresolvedExprListArg;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_EXPR_LIST_ARG;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DEFINITE, cantor::pb::ast::ENC_CLAUSE,
                                                cantor::pb::ast::ENC_CTOR);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_ENUM_ARG> {
        using type = UnresolvedEnumArg;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_ENUM_ARG;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DEFINITE, cantor::pb::ast::ENC_CLAUSE,
                                                cantor::pb::ast::ENC_CTOR);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_PROTO_ARG> {
        using type = UnresolvedProtoArg;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_PROTO_ARG;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DEFINITE, cantor::pb::ast::ENC_CLAUSE,
                                                cantor::pb::ast::ENC_CTOR);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_UDF_ARG> {
        using type = UnresolvedUdfArg;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_UDF_ARG;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DEFINITE, cantor::pb::ast::ENC_CLAUSE,
                                                cantor::pb::ast::ENC_CTOR);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_TABLE_DEF_ELEMENT> {
        using type = UnresolvedTableRef;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_TABLE_DEF_ELEMENT;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DEFINITE, cantor::pb::ast::ENC_DQL,
                                                cantor::pb::ast::ENC_VIRTUAL);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_MAP_CTOR_FUNC> {
        using type = UnresolvedCtorMapFuncExpr;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_MAP_CTOR_FUNC;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DISPATCH, cantor::pb::ast::ENC_DQL, pb::ast::ENC_DML,
                                                cantor::pb::ast::ENC_FUNC, cantor::pb::ast::ENC_CTOR);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_STRUCT_CTOR_FUNC> {
        using type = UnresolvedCtorStructFuncExpr;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_STRUCT_CTOR_FUNC;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DISPATCH, cantor::pb::ast::ENC_DQL, pb::ast::ENC_DML,
                                                cantor::pb::ast::ENC_FUNC, cantor::pb::ast::ENC_CTOR);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_UNION_CTOR_FUNC> {
        using type = UnresolvedCtorUnionFuncExpr;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_UNION_CTOR_FUNC;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DISPATCH, cantor::pb::ast::ENC_DQL, pb::ast::ENC_DML,
                                                cantor::pb::ast::ENC_FUNC, cantor::pb::ast::ENC_CTOR);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_ARRAY_CTOR_FUNC> {
        using type = UnresolvedCtorArrayFuncExpr;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_ARRAY_CTOR_FUNC;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DISPATCH, cantor::pb::ast::ENC_DQL, pb::ast::ENC_DML,
                                                cantor::pb::ast::ENC_FUNC, cantor::pb::ast::ENC_CTOR);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_SET_CTOR_FUNC> {
        using type = UnresolvedCtorSetFuncExpr;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_SET_CTOR_FUNC;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DISPATCH, cantor::pb::ast::ENC_DQL, pb::ast::ENC_DML,
                                                cantor::pb::ast::ENC_FUNC, cantor::pb::ast::ENC_CTOR);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_TUPLE_CTOR_FUNC> {
        using type = UnresolvedCtorTupleFuncExpr;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_TUPLE_CTOR_FUNC;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DISPATCH, cantor::pb::ast::ENC_DQL, pb::ast::ENC_DML,
                                                cantor::pb::ast::ENC_FUNC, cantor::pb::ast::ENC_CTOR);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_JSON_CTOR_FUNC> {
        using type = UnresolvedCtorJsonFuncExpr;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_JSON_CTOR_FUNC;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DISPATCH, cantor::pb::ast::ENC_DQL, pb::ast::ENC_DML,
                                                cantor::pb::ast::ENC_FUNC, cantor::pb::ast::ENC_CTOR);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_JSON_ARRAY_CTOR_FUNC> {
        using type = UnresolvedCtorJsonArrayFuncExpr;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_JSON_ARRAY_CTOR_FUNC;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DISPATCH, cantor::pb::ast::ENC_DQL, pb::ast::ENC_DML,
                                                cantor::pb::ast::ENC_FUNC, cantor::pb::ast::ENC_CTOR);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_ENUM_CTOR_FUNC> {
        using type = UnresolvedCtorEnumFuncExpr;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_ENUM_CTOR_FUNC;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DISPATCH, cantor::pb::ast::ENC_DQL, pb::ast::ENC_DML,
                                                cantor::pb::ast::ENC_FUNC, cantor::pb::ast::ENC_CTOR);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_PROTO_CTOR_FUNC> {
        using type = UnresolvedCtorProtoFuncExpr;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_PROTO_CTOR_FUNC;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DISPATCH, cantor::pb::ast::ENC_DQL, pb::ast::ENC_DML,
                                                cantor::pb::ast::ENC_FUNC, cantor::pb::ast::ENC_CTOR);
    };

    template<>
    struct ExpressionTypeTrait<cantor::pb::ast::ENT_UDF_CTOR_FUNC> {
        using type = UnresolvedCtorUdfFuncExpr;
        static constexpr cantor::pb::ast::ExprNodeType expr_type = cantor::pb::ast::ENT_UDF_CTOR_FUNC;
        static_assert(type::TYPE == expr_type, "type::TYPE must be equal to expr_type");
        static constexpr cantor::pb::ast::ExprNodeClass expr_class =
                cantor::pb::ast::expr_class_merge(cantor::pb::ast::ENC_DISPATCH, cantor::pb::ast::ENC_DQL, pb::ast::ENC_DML,
                                                cantor::pb::ast::ENC_FUNC, cantor::pb::ast::ENC_CTOR);
    };

    template<typename Visitor>
    struct IsDispatchExpr {
        static constexpr bool value = ExpressionTypeTrait<Visitor::TYPE>::expr_class & cantor::pb::ast::ENC_DISPATCH;
    };

    using all_expression_traits = cantor::common::TypeList<
        ExpressionTypeTrait<cantor::pb::ast::ENT_CONSTANT_EXPR>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_RANGE_VAR>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_ROW_EXPR>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_COLUMN_OPT>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_ENUM_ELEMENT>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_INDEX_OPT>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_COLUMN_DEF>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_PARTITION_OPT>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_PARTITION_RANGE>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_TABLE_PARTITION_OPTION>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_TABLE_OPT>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_CONSTRAINT>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_DATABASE_OPT>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_ALTER_SEPC>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_BY_ITEM>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_ORDER_BY>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_GROUP_BY>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_LIMIT_CLAUSE>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_INDIRECTION>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_SELECT_FIELD>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_INDEX_HINT>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_SELECT_STMT_OPT>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_TABLE_SOURCE>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_JOIN_NODE>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_SUB_QUERY_EXPR>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_EXISTS_SUB_QUERY_EXPR>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_COMMON_TABLE_EXPR>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_WITH_CLAUSE>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_COMPARE_SUBQUERY_EXPR>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_WHERE_CLAUSE>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_HAVING_CLAUSE>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_ASSIGNMENT>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_FIELD_ITEM>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_LINE_CLAUSE>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_FIELD_CLAUSE>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_FUNC_EXPR>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_FUNC_WHEN_CLAUSE>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_FUNC_CASE_WHEN_CLAUSE>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_INDEX_LOCK_OPT>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_ALGORITHM_OPT>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_VAR_ASSIGN>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_NAMED_TYPE>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_NAMESPACE_OPT>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_CLAUSE_WHEN_CASE>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_CLAUSE_WHEN>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_TABLE_NAME>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_COLUM_NAME>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_TYPE_NAME_URI>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_USER_IDENTIFIER>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_USER_SPEC>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_AUTH_OPTION>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_PRIV_LEVEL>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_PRIV_TYPE>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_MAP_PAIR>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_DICT_PAIR>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_MAP_ARG>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_DICT_ARG>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_EXPR_LIST_ARG>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_ENUM_ARG>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_PROTO_ARG>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_UDF_ARG>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_TABLE_DEF_ELEMENT>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_MAP_CTOR_FUNC>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_STRUCT_CTOR_FUNC>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_UNION_CTOR_FUNC>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_ARRAY_CTOR_FUNC>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_SET_CTOR_FUNC>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_TUPLE_CTOR_FUNC>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_JSON_CTOR_FUNC>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_JSON_ARRAY_CTOR_FUNC>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_ENUM_CTOR_FUNC>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_PROTO_CTOR_FUNC>,
        ExpressionTypeTrait<cantor::pb::ast::ENT_UDF_CTOR_FUNC>
    >;

    template<class T>
    struct IsDefinite {
        static constexpr bool value = T::expr_class & cantor::pb::ast::ENC_DEFINITE;
    };

    template<class T>
    struct IsDispatch {
        static constexpr bool value = T::expr_class & cantor::pb::ast::ENC_DISPATCH;
    };

    template<class T>
    struct IsIndirection {
        static constexpr bool value = T::expr_class & cantor::pb::ast::ENC_INDIRECTION;
    };

    template<class T>
    struct IsDdl {
        static constexpr bool value = T::expr_class & cantor::pb::ast::ENC_DDL;
    };

    template<class T>
    struct IsDql {
        static constexpr bool value = T::expr_class & cantor::pb::ast::ENC_DQL;
    };

    template<class T>
    struct IsCtor {
        static constexpr bool value = T::expr_class & cantor::pb::ast::ENC_CTOR;
    };

    using DefiniteList = cantor::common::FilteredUniqueList<IsDefinite, all_expression_traits>::type;

    using DispatchList = cantor::common::FilteredUniqueList<IsDispatch, all_expression_traits>::type;

    using DqlDefiniteList = cantor::common::FilteredUniqueList<IsDql, DefiniteList>::type;

    using AllVisitorType = cantor::common::ExtractList<all_expression_traits>::type;

    using DefiniteListVisitorType = cantor::common::ExtractList<DefiniteList>::type;

    using DispatchListVisitorType = cantor::common::ExtractList<DispatchList>::type;

    using DqlDefiniteListVisitorType = cantor::common::ExtractList<DqlDefiniteList>::type;

    template<typename Visitor>
    struct isInAllExprList : cantor::common::IsInList<Visitor, AllVisitorType> {
    };

    template<typename Expr>
    void list_impl(std::vector<cantor::pb::ast::ExprNodeType> &out) {
        out.push_back(Expr::TYPE);
    }

    template<class T>
    struct ListExprType;

    template<class... Arch>
    struct ListExprType<cantor::common::TypeList<Arch...> > {
        static std::vector<cantor::pb::ast::ExprNodeType> get_list() {
            std::vector<cantor::pb::ast::ExprNodeType> out;
            (void) std::initializer_list<int>{(list_impl<Arch>(out), 0)...};
            return out;
        }
    };

    inline std::vector<cantor::pb::ast::ExprNodeType> get_definite_list() {
        return ListExprType<DefiniteListVisitorType>::get_list();
    }

    inline std::vector<cantor::pb::ast::ExprNodeType> get_dispatch_list() {
        return ListExprType<DispatchListVisitorType>::get_list();
    }
} // namespace cantor::unresolved
